﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp.Util
{
	public static class ListUtil
	{
		public static void SplitExecute<TSource>(this IEnumerable<TSource> source, int size
			 , Action<List<TSource>> action, int tryCount = 3, int exptionSleep = 3000)
		{
			if (tryCount <= 0)
			{
				tryCount = 1;
			}

			var toatl = source.Count();
			for (int j = 0; j < toatl; j++)
			{
				var list = source.Skip(j * size).Take(size).ToList();
				if (list.Count <= 0)
				{
					break;
				}

				for (int i = 0; i < tryCount; i++)
				{
					try
					{
						action(list);
						var already = size * j + list.Count;
						ConsoleHelper.WriteSuccessLine($"{already} is ok  {(already * 1.0 / toatl).ToString("p2")}");
						break;
					}
					catch (Exception ex)
					{
						ConsoleHelper.WriteErrorLine(ex.ToString());
					}
				}
			}
		}

		public static void SplitExecuteParallFor<TSource>(this IEnumerable<TSource> source, int size
			, Action<List<TSource>> action, int tryCount = 3, int exptionSleep = 3000, int maxDegreeOfParallelism = 50)
		{
			if (tryCount <= 0)
			{
				tryCount = 1;
			}

			var total = source.Count();
			var already = 0;


			Parallel.For(0, total, new ParallelOptions() { MaxDegreeOfParallelism = maxDegreeOfParallelism }, (j) =>
			{
				try
				{
					var list = source.Skip(j * size).Take(size).ToList();
					if (list.Count > 0)
					{
						for (int i = 0; i < tryCount; i++)
						{
							try
							{
								action(list);
								already += list.Count;
								ConsoleHelper.WriteSuccessLine($"{already} is ok  {(already * 1.0 / total).ToString("p2")}");
								break;
							}
							catch (Exception ex)
							{

								ConsoleHelper.WriteErrorLine(ex.ToString());
							}
						}
					}
				}
				catch (Exception ex)
				{
					ConsoleHelper.WriteErrorLine(ex.ToString());
				}
			});

		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="TSource"></typeparam>
		/// <typeparam name="TResult"></typeparam>
		/// <param name="source"></param>
		/// <param name="size"></param>
		/// <param name="func"></param>
		/// <param name="tryCount"></param>
		/// <param name="exptionSleep"></param>
		/// <returns></returns>
		public static List<TResult> SplitExecute<TSource, TResult>(this IEnumerable<TSource> source, int size
			, Func<List<TSource>, List<TResult>> func, int tryCount = 3, int exptionSleep = 3000, int skipConsole = 0)
		{
			if (tryCount <= 0)
			{
				tryCount = 1;
			}

			List<TResult> result = new List<TResult>();

			var toatl = source.Count();
			for (int j = 0; j < toatl; j++)
			{
				var list = source.Skip(j * size).Take(size).ToList();
				if (list.Count <= 0)
				{
					break;
				}

				for (int i = 0; i < tryCount; i++)
				{
					try
					{
						var res = func(list);
						if (res?.Count > 0)
						{
							result.AddRange(res);
						}

						var already = size * j + list.Count;
						if (skipConsole == 0)
						{
							ConsoleHelper.WriteSuccessLine($"{already} is ok  {(already * 1.0 / toatl).ToString("p2")}");
						}
						break;
					}
					catch (Exception ex)
					{
						ConsoleHelper.WriteErrorLine(ex.ToString());
					}
				}
			}

			return result;
		}
	}
}
